package com.perceptivesoftware.licensing.server.util;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.gwtwidgets.server.spring.ServletUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.perceptivesoftware.licensing.client.dto.UserInitialDTO;
import com.perceptivesoftware.licensing.dao.TwUservalDaoExt;
import com.perceptivesoftware.licensing.domain.generated.TwUserval;
import com.perceptivesoftware.licensing.server.rpc.NoUservalForUserException;
import com.perceptivesoftware.licensing.server.rpc.UserNotAuthenticatedException;
import com.perceptivesoftware.licensing.server.user.UserAlreadyLoggedInException;
import com.perceptivesoftware.licensing.server.user.UserNotLoggedInException;
import com.perceptivesoftware.licensing.server.user.UserSessionTracker;
import com.perceptivesoftware.licensing.server.user.UserStaleSessionException;

@Transactional
@Component
public class SessionServiceUtil
{
	private final Logger logger = Logger.getLogger(getClass());

	@Autowired
	private TwUservalDaoExt nlUservalDaoExt;
	@Autowired
	private SecurityServiceUtil securityServiceUtil;
	@Autowired
	private UserSessionTracker userSessionTracker;
	@Autowired
	private UserUtil userUtil;
	@Autowired
	private PropertiesUtil propertiesUtil;

	public void wipeSession()
	{
		final HttpServletRequest request = ServletUtils.getRequest();
		final HttpSession session = request.getSession();
		session.setAttribute("perceptive_current_nlusercode", null);
		session.setAttribute("perceptive_current_nluserval", null);
	}

	public UserInitialDTO logon() throws UserAlreadyLoggedInException, NoUservalForUserException
	{
		final String username = getUsername().toUpperCase();

		List<TwUserval> userList = nlUservalDaoExt.findAllNotDeletedUservalsForUserName(username);

		final String userCode;
		if (userList.size() > 0)
		{
			userCode = userList.get(0).getUservalId();
		}
		else
		{
			// This shouldn't happen but if it does may be caused by case
			// difference
			logger.error("No user found with user name: " + getUsername());
			return null;
		}
		final String sessionID = userSessionTracker.login(username, userCode);
		try
		{
			final UserInitialDTO userInitialDTO = getUserInitialDTO();
			userInitialDTO.setUSessionID(sessionID);
			return userInitialDTO;
		}
		catch (final UserNotLoggedInException e)
		{
			logger.error("User not logged in at end of logon() method");// should
																		// not
																		// happen
			return null;
		}
	}

	public TwUserval getCurrentUserval() throws UserNotLoggedInException
	{
		final String username = ServerUtils.getSpringSecurityUsername().toUpperCase();
		final String currentUsercodeForUsername = userSessionTracker.getCurrentUsercodeForUsername(username);
		final TwUserval nlUserval = nlUservalDaoExt.findById(currentUsercodeForUsername);
		if (nlUserval == null)
		{
			throw new UserNotLoggedInException();
		}
		return nlUserval;
	}
	
	public TwUserval getCurrentApiUserval() throws UserNotLoggedInException
	{
		final String username = ServerUtils.getSpringSecurityUsername().toUpperCase();
		final TwUserval nlUserval = nlUservalDaoExt.getDefaultUservalForUsername(username);
		if (nlUserval == null)
		{
			throw new UserNotLoggedInException();
		}
		return nlUserval;
	}

	public void logout()
	{
		try
		{
			userSessionTracker.logoff(getUsername());
		}
		catch (final UserNotLoggedInException e)
		{}
		catch (final UserNotAuthenticatedException e)
		{}
	}

	public String getUsername()
	{
		return ServerUtils.getSpringSecurityUsername().toUpperCase();
	}

	/**
	 * Finds default user role for authenticated user and loads initial user settings.
	 * 
	 * @return
	 * @throws UserNotLoggedInException
	 */
	public UserInitialDTO getUserInitialDTO() throws NoUservalForUserException, UserNotLoggedInException
	{
		final TwUserval nlUserval = getCurrentUserval();
		final UserInitialDTO userInitialDTO = new UserInitialDTO(userUtil.getUserInfo(nlUserval));
		userInitialDTO.setPerceptivePermissions(securityServiceUtil.getPermissionsForUserval(nlUserval));
		userInitialDTO.setVersionInformation(propertiesUtil.getVersionString());		
		return userInitialDTO;
	}
	
	public UserInitialDTO getApiUserInitialDTO() throws NoUservalForUserException, UserNotLoggedInException
	{
		final TwUserval nlUserval = getCurrentApiUserval();
		final UserInitialDTO userInitialDTO = new UserInitialDTO(userUtil.getUserInfo(nlUserval));
		userInitialDTO.setPerceptivePermissions(securityServiceUtil.getPermissionsForUserval(nlUserval));
		userInitialDTO.setVersionInformation(propertiesUtil.getVersionString());		
		return userInitialDTO;
	}

	public UserInitialDTO loadUserDTO(String optionalSessionID) throws UserNotLoggedInException, UserNotAuthenticatedException
	{
		final UserInitialDTO userInitialDTO = getUserInitialDTO();
		userInitialDTO.setUSessionID(optionalSessionID);
		return userInitialDTO;
	}

	public String heartbeat(String sessionID)
	{
		try
		{
			userSessionTracker.updateHeartbeatTimestamp(sessionID, getUsername());
			return null;
		}
		catch (final UserNotLoggedInException e)
		{
			return "User not logged in";
		}
		catch (final UserNotAuthenticatedException e)
		{
			return "User not authenticated";
		}
		catch (final UserStaleSessionException e)
		{
			return "This session is no longer valid.";
		}
	}

	public boolean isValidUser()
	{
		List<TwUserval> userList = nlUservalDaoExt.findAllNotDeletedUservalsForUserName(getUsername());

		if (userList.size() > 0)
		{
			return true;
		}
		else
		{
			// This can be caused by case differences
			return false;
		}
	}
}